package com.hbnrtech.sip.gb28181.util;

import lombok.extern.slf4j.Slf4j;

import java.util.Objects;

/**
 * @author liuduo
 * @date 2025-04-22 18:38
 */
@Slf4j
public class SsrcUtil {
    private static final String SSRC_PREFIX_PLAY = "01";
    private static final String SSRC_PREFIX_PLAYBACK = "02";
    private static final String SSRC_PREFIX_PUSH = "03"; // 用于区分推流

    // SSRC 后 8 位的最大取值范围 + 1 (模数)
    private static final int MAX_SSRC_COUNT = 99999999;

    /**
     * 私有构造函数，防止实例化
     */
    private SsrcUtil() {
        throw new IllegalStateException("Utility class");
    }

    /**
     * 生成实时直播的 SSRC。
     *
     * @param streamId 流标识符 (必须是可转换为整数的字符串)
     * @return 10 位的 SSRC 字符串 (例如 "0100000123")
     */
    public static String getPlaySsrc(String streamId) {
        Objects.requireNonNull(streamId, "streamId cannot be null");
        int ssrcNum = Integer.parseInt(streamId) % MAX_SSRC_COUNT;
        // 保证 ssrcNum 为非负数 (虽然对于正数 % 正数结果总是正数，但以防万一)
        if (ssrcNum < 0) {
            ssrcNum += MAX_SSRC_COUNT;
        }
        return SSRC_PREFIX_PLAY + String.format("%08d", ssrcNum);
    }

    /**
     * 生成历史回放的 SSRC。
     *
     * @param streamId 流标识符 (必须是可转换为整数的字符串)
     * @return 10 位的 SSRC 字符串 (例如 "0200000456")
     */
    public static String getPlayBackSsrc(String streamId) {
        Objects.requireNonNull(streamId, "streamId cannot be null");
        int ssrcNum = Integer.parseInt(streamId) % MAX_SSRC_COUNT;
        if (ssrcNum < 0) {
            ssrcNum += MAX_SSRC_COUNT;
        }
        return SSRC_PREFIX_PLAYBACK + String.format("%08d", ssrcNum);
    }

    /**
     * 生成设备/平台推流的 SSRC (模拟 wvp 中的逻辑)。
     *
     * @param streamId 流标识符 (必须是可转换为整数的字符串)
     * @return 10 位的 SSRC 字符串 (例如 "0300000789")
     */
    public static String getPushStreamSsrc(String streamId) {
        Objects.requireNonNull(streamId, "streamId cannot be null");
        int ssrcNum = Integer.parseInt(streamId) % MAX_SSRC_COUNT;
        if (ssrcNum < 0) {
            ssrcNum += MAX_SSRC_COUNT;
        }
        return SSRC_PREFIX_PUSH + String.format("%08d", ssrcNum);
    }

    /**
     * 检查给定的 SSRC 是否表示实时直播。
     *
     * @param ssrc 待检查的 SSRC 字符串
     * @return 如果是实时直播 SSRC 返回 true，否则 false
     */
    public static boolean isPlay(String ssrc) {
        return ssrc != null && ssrc.length() == 10 && ssrc.startsWith(SSRC_PREFIX_PLAY);
    }

    /**
     * 检查给定的 SSRC 是否表示历史回放。
     *
     * @param ssrc 待检查的 SSRC 字符串
     * @return 如果是历史回放 SSRC 返回 true，否则 false
     */
    public static boolean isPlayBack(String ssrc) {
        return ssrc != null && ssrc.length() == 10 && ssrc.startsWith(SSRC_PREFIX_PLAYBACK);
    }

    /**
     * 检查给定的 SSRC 是否表示推流。
     *
     * @param ssrc 待检查的 SSRC 字符串
     * @return 如果是推流 SSRC 返回 true，否则 false
     */
    public static boolean isPush(String ssrc) {
        return ssrc != null && ssrc.length() == 10 && ssrc.startsWith(SSRC_PREFIX_PUSH);
    }

    /**
     * 从 SSRC 中提取原始的 streamId 计算基数 (后 8 位)。
     * 注意：这不一定能完全还原原始的 streamId，因为生成过程中使用了取模运算。
     *
     * @param ssrc 10 位的 SSRC 字符串
     * @return SSRC 的后 8 位数字部分，如果 SSRC 格式无效则返回 null 或抛出异常 (这里选择返回 null)
     */
    public static String getStreamIdSuffix(String ssrc) {
        if (ssrc != null && ssrc.length() == 10) {
            try {
                // 验证前两位是数字，后八位是数字
                Integer.parseInt(ssrc.substring(0, 2));
                String suffix = ssrc.substring(2);
                Integer.parseInt(suffix); // 验证后八位也是数字
                return suffix;
            } catch (NumberFormatException e) {
                // 格式不正确
                return null;
            }
        }
        return null;
    }

    /**
     * 辅助方法：生成用于 SSRC 计算的 streamId
     * 实际的 streamId 生成逻辑可能更复杂，这里仅作示例。
     * wvp 中可能直接用某个唯一 ID，或者 deviceId + channelId 的某种组合。
     *
     * @param deviceId  设备 ID
     * @param channelId 通道 ID
     * @return 一个用于 SSRC 计算的 streamId 字符串 (需要保证是数字)
     */
    public static String generateStreamId(String deviceId, String channelId) {
        // 示例：简单地取 deviceId 和 channelId 的数字部分拼接
        // 注意：这种方式非常简化，实际项目中 streamId 的生成可能需要确保证唯一性且全数字
        // 例如：可以考虑取 deviceId 后几位 + channelId 后几位，或者使用哈希后取数值等
        String devNum = deviceId.replaceAll("\\D+", ""); // 移除非数字
        String chanNum = channelId.replaceAll("\\D+", ""); // 移除非数字

        // 简单拼接，可能超长，需要截断或采取其他策略确保是有效整数范围
        // 这里的实现需要根据 wvp 的具体逻辑调整
        String combined = devNum + chanNum;
        if (combined.isEmpty()) {
            // 提供一个默认值或者抛出异常，防止空字符串导致 parseInt 失败
            return "0";
        }
        // 如果拼接后过长，可能导致 Integer.parseInt 溢出，需要处理
        // 简单的处理方式：截取一部分，但这可能增加冲突概率
        if (combined.length() > 9) { // Integer 最大值约 21亿 (10位)，安全起见用 9 位
            combined = combined.substring(combined.length() - 9);
        }
        // 再次确保是非空
        if (combined.isEmpty()) {
            return "0";
        }

        return combined;
    }

    // --- 使用示例 ---
    public static void main(String[] args) {
        // 模拟 wvp 中的设备 ID 和通道 ID
        String deviceId = "34020000001320000001";
        String channelId = "34020000001310000005";

        // 1. 生成 streamId (使用辅助方法，实际应参考 wvp 具体实现)
        String streamIdForSsrc = generateStreamId(deviceId, channelId);
        System.out.println("Generated Stream ID for SSRC calculation: " + streamIdForSsrc);


        try {
            // 2. 生成各种类型的 SSRC
            String playSsrc = SsrcUtil.getPlaySsrc(streamIdForSsrc);
            String playbackSsrc = SsrcUtil.getPlayBackSsrc(streamIdForSsrc);
            String pushSsrc = SsrcUtil.getPushStreamSsrc(streamIdForSsrc);

            System.out.println("Play SSRC:       " + playSsrc);
            System.out.println("Playback SSRC:   " + playbackSsrc);
            System.out.println("Push SSRC:       " + pushSsrc);

            // 3. 验证 SSRC 类型
            System.out.println("Is " + playSsrc + " Play SSRC?      " + SsrcUtil.isPlay(playSsrc));
            System.out.println("Is " + playSsrc + " Playback SSRC?  " + SsrcUtil.isPlayBack(playSsrc));
            System.out.println("Is " + playbackSsrc + " Playback SSRC? " + SsrcUtil.isPlayBack(playbackSsrc));
            System.out.println("Is " + pushSsrc + " Push SSRC?      " + SsrcUtil.isPush(pushSsrc));


            // 4. 提取 SSRC 后缀
            System.out.println("Stream ID suffix from " + playSsrc + ": " + SsrcUtil.getStreamIdSuffix(playSsrc));

            // 5. 测试无效输入
            System.out.println("Is '12345' Play SSRC? " + SsrcUtil.isPlay("12345")); // false (长度不对)
            System.out.println("Is 'XX00000001' Play SSRC? " + SsrcUtil.isPlay("XX00000001")); // false (前缀不对)

            // 测试 streamId 非数字的情况 (会抛出 NumberFormatException)
            // String invalidSsrc = SsrcUtil.getPlaySsrc("abc");
            // System.out.println("Invalid SSRC: " + invalidSsrc);

        } catch (NumberFormatException e) {
            System.err.println("Error: The provided streamId is not a valid integer string. " + e.getMessage());
        } catch (NullPointerException e) {
            System.err.println("Error: The provided streamId is null. " + e.getMessage());
        }
    }
}